package com.yunhe.authority.repository.authority;

import com.yunhe.authority.domain.authority.Firm;
import com.yunhe.authority.domain.base.FirmType;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

/**
 * 单位数据仓库
 * @desc 单位数据仓库定义
 * @author liuronglei
 */
@Repository
public interface FirmRepository extends Neo4jRepository<Firm, Long> {
    /**
     * 根据单位编号获得单位对象
     * @param name 单位编号
     */
    Firm findByName(String name);

    /**
     * 根据单位代码获得单位对象
     * @param code 单位代码
     */
    Firm findByCode(Long code);

    /**
     * 获得所有单位（支持10层树形）
     */
    //@Query("MATCH (n:Firm) WHERE not ()-[:HAS_CHILD]->(n) WITH n MATCH p=(n)-[:HAS_CHILD*0..9]->(m) RETURN p, ID(n)")
    @Query("MATCH (n:Firm) WHERE not ()-[:HAS_CHILD]->(n) WITH n " +
            "MATCH p=(n)-[:HAS_CHILD*0..9]-(m)-[:AREA_OF|:FIRMTYPE_OF|:HOMEPAGE_OF|:HAS_STATION*0..1]->()  RETURN p,ID(n)")
    Iterable<Firm> findFirms();

    /**
     * 添加子单位关系
     * @param parentId 父单位ID
     * @param childId 子单位ID
     */
    @Query("start parent=node({parentId}),child=node({childId}) create (parent)-[:HAS_CHILD]->(child)")
    void addChildRelation(@Param("parentId") Long parentId, @Param("childId") Long childId);

    /**
     * 删除子单位关系
     * @param parentId 父单位ID
     * @param childId 子单位ID
     */
    @Query("start parent=node({parentId}),child=node({childId}) match (parent)-[r:HAS_CHILD]->(child) delete r")
    void delChildRelation(@Param("parentId") Long parentId, @Param("childId") Long childId);

    /**
     * 绑定单位有权限的菜单
     * @param firmId 单位ID
     * @param menuId 菜单ID
     */
    @Query("start firm=node({firmId}),menu=node({menuId}) create (firm)-[:HAS_MENU]->(menu)")
    void bindMenu(@Param("firmId") Long firmId, @Param("menuId") Long menuId);

    /**
     * 绑定单位有权限的多个菜单
     * @param firmId
     * @param menuIds
     */
    @Query("start firm=node({firmId}) match (menu:Menu) where ID(menu) in {menuIds} create (firm)-[:HAS_MENU]->(menu)")
    void bindMenus(@Param("firmId") Long firmId, @Param("menuIds") List menuIds);

    /**
     * 绑定单位有权限的菜单
     * @param firmId 单位ID
     * @param menuId 菜单ID
     */
    @Query("start firm=node({firmId}),menu=node({menuId}) create (firm)-[:HAS_MENU_APP]->(menu)")
    void bindAppMenu(@Param("firmId") Long firmId, @Param("menuId") Long menuId);

    /**
     * 解绑单位有权限的菜单
     * @param firmId  单位ID
     * @param menuId  菜单ID
     */
    @Query("start firm=node({firmId}),menu=node({menuId}) match(firm)-[r]->(menu) delete r")
    void unbindMenu(@Param("firmId") Long firmId, @Param("menuId") Long menuId);

    /**
     * 解绑单位有权限的全部菜单
     * @param firmId 单位ID
     */
    @Query("start firm=node({firmId}) match(firm)-[r:HAS_MENU]->() delete r")
    void unbindAllMenus(@Param("firmId") Long firmId);

    /**
     * 根据单位ID查询单位
     * @param id 单位ID
     */
    @Query("match p=()<-[:FIRMTYPE_OF*0..1]-(firm)-[:HAS_CHILD*0..9]->(n)-[:AREA_OF|:FIRMTYPE_OF|:HOMEPAGE_OF*0..9]->(m) where ID(firm)={id} return p")
    Optional<Firm> findById(@Param("id") Long id);

    /**
     * 解绑父单位
     * @param id  单位ID
     */
    @Query("start firm=node({id}) match(parentFirm)-[r:HAS_CHILD]->(firm) delete r")
    void unbindParentFirmById(@Param("id") Long id);

    /**
     * 单位绑定单位类型
     * @param id 单位ID
     * @param firmTypeId 单位类型ID
     */
    @Query("start n=node({id}),m=node({firmTypeId}) create (n)-[:FIRMTYPE_OF]->(m)")
    void bindFirmTypeById(@Param("id") Long id, @Param("firmTypeId") Long firmTypeId);

    /**
     * 单位解绑单位类型
     * @param id 单位ID
     */
    @Query("start n=node({id}) match (n)-[r:FIRMTYPE_OF]->() delete r")
    void unbindFirmTypeById(@Param("id") Long id);

    /**
     * 根据单位获得单位类型
     * @param id ID
     */
    @Query("start n=node({id}) match(n)-[:FIRMTYPE_OF]->(m) return m")
    FirmType findFirmTypeByFirmId(@Param("id") Long id);

    /**
     * 根据单位类型获得单位
     * @param firmTypeId 单位类型ID
     */
    @Query("start n=node({firmTypeId}) match p=()-[:AREA_OF]-(f:Firm)-[:FIRMTYPE_OF]->(n) return p")
    Iterable<Firm> findFirmsByFirmTypeId(@Param("firmTypeId") Long firmTypeId);

    /**
     * 根据ID绑定子单位
     * @param parentId 父单位ID
     * @param childId 子单位ID
     */
    @Query("start n=node({parentId}),m=node({childId}) create (n)-[:HAS_CHILD]->(m)")
    void bindChildFirmById(@Param("parentId") Long parentId, @Param("childId") Long childId);

//    /**
//     * 根据单位单位获取单位拥有的设备
//     * @param firmCode 单位代码
//     */
//    @Query("match(f:Firm{code:{firmCode}})-[:HAS_RESOURCE]->(dev) with distinct dev " +
//            " return ID(dev) as id,dev.title as title,dev.name as name,dev.code as code,labels(dev) as type")
//    Iterable<Dev> getDevsByFirm(@Param("firmCode") Long firmCode);

    /**
     * 根据设备ID找单位
     * @param devId 设备ID
     */
    @Query("start n=node({devId}) match(f:Firm)-[:HAS_RESOURCE]->(n) return f")
    Iterable<Firm> findFirmByDevId(@Param("devId") Long devId);

    /**
     * 根据电站ID查找所属单位
     * @param stationId 电站ID
     */
    @Query("match p=()<-[:AREA_OF|:FIRMTYPE_OF|:HOMEPAGE_OF]-(f:Firm)-[:HAS_STATION]->(s:Station) where ID(s)={stationId} return p")
    Firm findFirmByStationId(@Param("stationId") Long stationId);

    /**
     * 单位绑定电站
     * @param id 单位ID
     * @param stationId 电站ID
     */
    @Query("start f=node({id}),s=node({stationId}) create (f)-[:HAS_STATION]->(s)")
    void bindStation(@Param("id") Long id, @Param("stationId") Long stationId);

    /**
     * 单位解绑电站
     * @param id 单位ID
     * @param stationId 电站ID
     */
    @Query("match(f:Firm)-[r]->(s:Station) where ID(f)={id} and ID(s)={stationId} delete r")
    void unbindStation(@Param("id") Long id, @Param("stationId") Long stationId);

    /**
     * 单位解绑所有电站
     * @param id 单位ID
     */
    @Query("match(f:Firm)-[r]->(s:Station) where ID(f)={id} delete r")
    void unbindAllStations(@Param("id") Long id);

    @Query("match(f:Firm)-[:HAS_RESOURCE]->(dev{code:{devCode}}) return f limit 1")
    Firm findFirmByDevCode(@Param("devCode") Long devCode);

    @Query("match(f:Firm)-[:HAS_STATION]->(s:Station) where s.code={stationCode} return f limit 1")
    Firm findByStationCode(@Param("stationCode") Long stationCode);

    /**
     * 单位解绑静态数据
     * @param fsdId
     * @param id
     */
    @Query("match(f:Firm)-[r:FirmStaticData_OF]->(fsd:FirmStaticData) where ID(f)={id} and ID(fsd)={fsdId} delete r,fsd")
    void unbindFirmStaticData(@Param("fsdId") Long fsdId,@Param("id") Long id);

    /**
     * 单位绑定静态数据
     * @param fsdId
     * @param id
     */
    @Query("start f=node({id}),fsd=node({fsdId}) create (f)-[:FirmStaticData_OF]->(fsd)")
    void bindFirmStaticData(@Param("fsdId") Long fsdId,@Param("id") Long id);

    @Query("match (f:Firm)-[:HAS_ROLE]->(role:Role) where ID(role) IN {roleIds} return f")
    Iterable<Firm> findFirmsByRoleIds(@Param("roleIds") List<Long> roleIds);

    @Query("match (f:Firm) return f order by f.sn desc,f.createTime asc")
    Iterable<Firm> findAllFirms();

    @Query("match (f:Firm{system:{code}}) return f order by f.sn asc,f.createTime asc")
    Iterable<Firm> findBySystem(@Param("code") String code);

    @Query("match(f:Firm)-[:HAS_STATION]->(s:Station) where ID(s)={stationId} return f")
    Firm findByStationId(@Param("stationId") Long stationId);
}